import { getAction, postAction,uploadAction,deleteAction } from '@/api/manage'
import YchConstant from "@/api/YchConstant";
import {handleCreateFunc, handleExecFunc} from '@/utils/actions'
import config from '@/settings'

export const FormMixin = {
  data () {
    return {
      id: this.formId,
      confirmLoading: 0,
      url: {
        getData: YchConstant.PREFIX_EFORM + '/engine/formEngine/getData',
        saveData: YchConstant.PREFIX_EFORM + '/engine/formEngine/saveData',
        uploadAction: YchConstant.PREFIX_SYSTEM + "/common/upload",
        deleteFileUrl: YchConstant.PREFIX_SYSTEM + "/common/deleteFile",
      },
      jsonData: {},//表单模型
      jsonModel: [],//需要保存的key的集合
      allDataSource: {},//所有初始化数据
      isFlow: false,//是否流程
      data: {},//原始data
      dictMap: {},
      elValue: {},
      dsCode: {},
      readOnly: false,
      syncNum: 0, // 防止异步
      fileList:[],//上传文件列表,跟字段不绑定的文件上传控件
      uploadedFileList:[],//已上传文件列表
      formValues: null, // 主表数据，用于组合页面中的主子表联动
      uploadTimestamp:'',//上传时间戳
      saveParameter: {}, // 保存数据时的自定义参数
      enableDraft:false,//启用草稿
    }
  },
  inject: {
    closeCurrent: {
      from: 'closeCurrent',
      default: () => {
        return () => {
        }
      }
    },
  },
  methods: {
    getItemObj(key, jsonData){
      let jsonList = jsonData.list
      return this.$ychCommon.findItemByKey(jsonList, key);
    },
    setHidden(tableName, modelName, isHidden, jsonData) {
      let jsonList = jsonData.list
      this.hiddenModel(jsonList, tableName, modelName, isHidden)
    },
    hiddenModel(jsonList, tableName, modelName, isHidden) {
      if (!jsonList) {
        return
      }
      jsonList.forEach(vo => {
        if (vo.dataId && vo.dataId == modelName) {
          vo.options.hidden = isHidden
        } else if (vo.model && vo.tableName == tableName && vo.model == modelName) {
          vo.options.hidden = isHidden
        } else if (vo.type == 'editableTable' && vo.tableName && vo.tableName == tableName) {
          vo.options.hidden = isHidden
        } else if (vo.tab && vo.tab == modelName) {
          vo.hidden = isHidden
        } else {
          this.hiddenModel(vo.list, tableName, modelName, isHidden)
          this.hiddenModel(vo.trs, tableName, modelName, isHidden)
          this.hiddenModel(vo.tds, tableName, modelName, isHidden)
          this.hiddenModel(vo.columns, tableName, modelName, isHidden)
          this.hiddenModel(vo.tabs, tableName, modelName, isHidden)
        }
      })
    },
    getFileList(formData){
      this.fileList = []
      this.dealFileList(this.jsonData.list,this.fileList,formData)
    },
    dealFileList (jsonList,fileList,formData) {
      if (!jsonList) {
        return
      }
      jsonList.forEach(vo => {
        if ((vo.type == 'uploadFile' || vo.type == 'uploadImg') && vo.dataId) {
          let fileStr = formData[vo.dataId]
          if(fileStr && fileStr!=''){
            fileList.push(fileStr)
          }
        }else {
          this.dealFileList(vo.list,fileList,formData)
          this.dealFileList(vo.trs,fileList,formData)
          this.dealFileList(vo.tds,fileList,formData)
          this.dealFileList(vo.columns,fileList,formData)
          this.dealFileList(vo.tabs,fileList,formData)
        }
      })
    },
    add () {
      this.beforeOpen().then(() => {
        this.readOnly = false
        this.open(this.url.getData + '?formKey=' + this.formCode)
      });
    },
    edit () {
      this.beforeOpen().then(() => {
        this.readOnly = false
        if(!this.id){
          this.jsonData = {}
          this.readOnly = true
          return;
        }
        // TODO 后续优化
        this.open(this.url.getData + '?formKey=' + this.formCode + '&id=' + this.id)
      });
    },
    detail () {
      this.beforeOpen().then(() => {
        this.readOnly = true
        if(!this.id){
          this.jsonData = {}
          return;
        }
        // TODO 后续优化
        this.open(this.url.getData + '?formKey=' + this.formCode + '&id=' + this.id)
      });
    },
    beforeOpen() {
      this.syncNum ++
      const syncNum = this.syncNum
      return new Promise((resovle, reject) => {
        let url = this.url.getData + '?formKey=' + this.formCode
        getAction(url, undefined).then((res) => {
          // 防止异步
          if(syncNum !== this.syncNum){
            return;
          }
          if (res.success) {
            // 新页签打开，设置标题
            this.$emit('setFormTitle', res.result.formName)

            const jsonData = JSON.parse(res.result.html)
            if (jsonData && jsonData.config && jsonData.config.beforeOpen) {
              // 打开前事件
              const func = handleCreateFunc(jsonData.config.beforeOpen, this)
              const func_result = handleExecFunc(func, { jsonData }, function(){
                resovle(true)
              })
              if (!func_result) return
            }
            resovle(true)
          } else {
            this.messageUtil.warning(res.message)
            resovle(false)
          }
        }).finally(() => {
        })
      })
    },
    open (url) {
      this.jsonData = {};
      this.jsonModel = [];
      this.allDataSource = {};
      this.data = {};
      this.dictMap = {};
      this.elValue = {};
      this.dsCode = {};

      this.confirmLoading ++
      this.$emit("addParentSpinning")
      getAction(url, undefined).then((res) => {
        if (res.success) {
          const jsonData = JSON.parse(res.result.html)
          if(jsonData && jsonData.config && jsonData.config.beforeLoad){
            // 加载前事件
            const _that = this
            const func = handleCreateFunc(jsonData.config.beforeLoad, this)
            const func_result = handleExecFunc(func, {url, res, jsonData}, function(){
              _that.openCallback(res, jsonData, url);
            })
            if(!func_result) return;
          }
          this.openCallback(res, jsonData, url);
        } else {
          this.messageUtil.warning(res.message)
        }
      }).finally(() => {
        this.confirmLoading --
        this.$emit("delParentSpinning")
      })
    },
    openCallback(res, jsonData, url){
      this.dictMap = res.result.dictModelMap
      this.elValue = res.result.elValue
      this.dsCode = res.result.dsCode

      // 传递父数据
      if(this.parentValue){
        Object.keys(this.parentValue).forEach(key => {
          this.elValue["parent." + key] = this.parentValue[key]
        });
      }

      // disQueryDB 不查询数据库
      this.data = res.result.data
      if (this.disQueryDB) {
        const key = Object.keys(res.result.data)[0];
        Object.assign(this.data[key], this.record)
      }
      this.findAllTableData(this.data, 0)

      if (this.readOnly && jsonData && jsonData.list) {
        this.readOnlyModel(jsonData.list)
      }
      this.jsonData = jsonData

      // 隐藏弹框的按钮栏
      if (jsonData && jsonData.config && jsonData.config.hideDialogButtons) {
        this.$emit("hideDialogButtons")
      }
      this.formValues = this.data[Object.keys(this.data)[0]]
      //启用草稿并且有dataStatus并且dataStatus值不为1时显示 保存草稿按钮
      this.enableDraft = config.enableDraft && this.formValues.hasOwnProperty("dataStatus") && (this.formValues.dataStatus=='0' ||  this.func === 'add')
      this.$emit("setEnableDraft",this.enableDraft)
      // 初始化后触发联动事件，用于子表新增
      if (this.func !== 'add' && typeof this.setPk === "function") {
        this.setPk();
      }

      if(jsonData && jsonData.config && jsonData.config.afterLoad){
        // 加载后事件
        const func = handleCreateFunc(jsonData.config.afterLoad, this)
        handleExecFunc(func, {url, res, jsonData})
      }
    },
    readOnlyModel (jsonList) {
      if (!jsonList) {
        return
      }
      jsonList.forEach(vo => {
        if (vo.options && typeof vo.options.disabled !== "undefined" && typeof vo.options.disabledBak === "undefined") {
          // 备份原始数据
          vo.options.disabledBak = vo.options.disabled
        }
        if (vo.dataId) {
          vo.options.disabled = true
        } else if (vo.model) {
          vo.options.disabled = true
        } else if (vo.type == 'editableTable' && vo.tableName) {
          vo.options.disabled = true
        } else {
          this.readOnlyModel(vo.list)
          this.readOnlyModel(vo.trs)
          this.readOnlyModel(vo.tds)
          this.readOnlyModel(vo.columns)
          this.readOnlyModel(vo.tabs)
        }
      })
    },
    /**
     * 保存数据方法
     * @param func 回调函数
     * @param processDefId 流程定义id
     * @param isDraft 是否草稿 true:是 false 否
     */
    save (func, processDefId,isDraft) {
      //保存草稿不校验必填
      if(config.enableDraft && isDraft==true){
        this.handleSubmit(this.$refs.KFormBuild.getDataNotCheck(), func, processDefId,isDraft && !processDefId)
      }else{
        this.handleSubmit(this.$refs.KFormBuild.getData(), func, processDefId)
      }

    },
    findAllTableData (data, isMain, tableName) {
      //将所有数据封装进一个对象中
      Object.keys(data).forEach(key => {
        const value = data[key]
        if (value instanceof Object && value.constructor == Object) {
          //子对象，循环调用
          this.findAllTableData(value, isMain + 1, key)
        } else if (value instanceof Object && value.constructor == Array) {
          //子表
          this.allDataSource[key] = value
        } else {
          if (isMain == 1) {
            this.allDataSource[key] = value
          } else {
            this.allDataSource[tableName + '-' + key] = value
          }
        }
      })
    },
    //data是原始数据，用来查找对象关型，allData是表单数据，用来保存的实际数据
    createBoData (data, allData, isMain, tableName) {
      const result = new Object()
      Object.keys(data).forEach(key => {
        const value = data[key]
        if (value instanceof Object && value.constructor == Object) {
          //子对象，循环调用
          result[key] = this.createBoData(value, allData, isMain + 1, key) || {}
        } else if (value instanceof Object && value.constructor == Array) {
          //子表
          result[key] = allData[key] || []
        } else if (key == 'id' && value) {
          result[key] = value
        } else {
          let modelKey
          if (isMain == 1) {
            modelKey = key
          } else {
            modelKey = tableName + '-' + key
          }
          if (this.jsonModel.indexOf(modelKey) != -1 && allData.hasOwnProperty(key)) {
            result[key] = allData[key]
          }
        }
      })
      return result
    },
    addModelKey (modelKey) {
      this.jsonModel.push(modelKey)
    },
    trimData(formData){
      let that = this
      if(formData){
        Object.keys(formData).forEach(key=>{
          if(formData[key] && typeof(formData[key])=='string'){
            formData[key] = formData[key].trim()
          }else if(formData[key] instanceof Object && formData[key].constructor == Array && formData[key].length){
            formData[key].forEach(item=>{
              that.trimData(item)
            })
          }else if (formData[key] instanceof Object && formData[key].constructor == Object){
            that.trimData(formData[key])
          }
        })
      }
    },
    handleSubmit (p, func, processDefId,isDraft) {
      this.$emit("addParentSpinning")
      p.then(res => {
        let httpurl = this.url.saveData + '?formKey=' + this.formCode
        if (processDefId) {
          httpurl += '&processDefId=' + processDefId
        }
        httpurl += '&isFlow=' + this.isFlow

        //处理附件
        this.getFileList(res)
        //去空格
        this.trimData(res)
        const formData = this.createBoData(this.data, res, 0)

        const boKey = Object.keys(formData)[0]

        if (this.id) {
          formData[boKey].id = this.id
        }
        //给草稿状态字段时赋值，保存草稿调用时赋值为 0 否则赋值为 1
        if(isDraft){
          formData[boKey].dataStatus = '0'
        }else{
          formData[boKey].dataStatus = '1'
        }
        this.formValues = formData[boKey]

        // 只有新增页面才需要关联外键
        if (!this.id && this.fks && this.fks.length > 0) {
          this.fks.forEach(fk => {
            formData[boKey][fk.colCode] = fk.queryValue
          })
        }

        // 保存前事件
        if(this.jsonData && this.jsonData.config && this.jsonData.config.beforeSave){
          const _that = this;
          const func_ext = handleCreateFunc(this.jsonData.config.beforeSave, this)
          const func_result = handleExecFunc(func_ext, {formData, boKey, p, func, processDefId, httpurl, res}, function(){
            _that.handleSubmitCallback(httpurl, formData, func, boKey, p, processDefId)
          })
          if(!func_result) return;
        }
        this.handleSubmitCallback(httpurl, formData, func, boKey, p, processDefId)
      }).catch(error => {
      }).finally(() => {
        this.$emit("delParentSpinning")
      })
    },
    handleSubmitCallback(httpurl, formData, func, boKey, p, processDefId) {
      if (this.saveInPage) {
        // 仅在页面暂时存储，用于子表添加
        if (typeof func === 'function') {
          func(this.id)
        } else {
          // 如果没有回调，一般是正常保存
          // 如果有回调，一般是启动或提交
          this.messageUtil.success(this.$t('m.eform.formDesign.label.bao-cun-cheng-gong'))
        }
        this.$emit('refreshParent', this.id, this.tableName, formData)

        // TODO 完善子表的弹框填写功能

      } else {
        // 保存入库
        this.confirmLoading ++
        this.$emit("addParentSpinning")
        postAction(httpurl, {formData: formData, saveParameter: this.saveParameter}).then((res) => {
          if (res.success) {
            //上传及删除附件
            this.handleUpload(res,httpurl,formData, func, boKey, p, processDefId)
          } else {
            this.messageUtil.warning(res.message)
          }
        }).finally(() => {
          this.confirmLoading --
          this.$emit("delParentSpinning")
        })
      }
    },
    refreshParent(){
      // 刷新父页面，id和tableName是用于刷新树节点
      this.$emit('refreshParent', this.id, this.tableName)
    },
    close(){
      this.$emit("close")
    },
    //附件上传回调
    uploadCallback(res,httpurl,formData, func, boKey, p, processDefId){
      //保存成功提示信息脚本
      let saveSucessMsg = ""
      if(this.jsonData && this.jsonData.config && this.jsonData.config.saveSucessMsg){
        const func_ext = handleCreateFunc(this.jsonData.config.saveSucessMsg, this)
        saveSucessMsg = handleExecFunc(func_ext, {formData, boKey, p, func, processDefId, httpurl, res})
      }
      if (!this.id) {
        this.id = res.result

        this.formValues.id = this.id
        // 新增后触发联动事件，用于子表新增
        if (typeof this.setPk === "function") {
          this.setPk();
        }
      }
      if (typeof func === 'function') {
        func(this.id,saveSucessMsg)
      } else {
        // 如果没有回调，一般是正常保存
        // 如果有回调，一般是启动或提交
        if(saveSucessMsg){
          this.messageUtil.success(saveSucessMsg)
        }else{
          this.messageUtil.success(res.message)
        }
      }
      // 刷新父页面，id和tableName是用于刷新树节点
      this.$emit('refreshParent', this.id, this.tableName)

      this.$emit("setRefresh", {
        tableName: this.tableName,
        type: 'form',
      })
      // 保存后事件
      if (this.jsonData && this.jsonData.config && this.jsonData.config.afterSave) {
        const func_ext = handleCreateFunc(this.jsonData.config.afterSave, this)
        handleExecFunc(func_ext, {formData, boKey, p, func, processDefId, httpurl, res})
      }
    },
    /**
     * 手动上传附件
     */
    handleUpload(saveRes,httpurl,formData, func, boKey, p, processDefId) {
      let that = this;
      //上传文件列表
      let addFileList = []
      //删除文件列表
      let delFileList = []
      that.fileList.forEach(item=>{
        if(item && item.length>0){
          item.forEach(file=>{
            if(!file.uploaded && file.originFileObj && !file.delete){
                let added = that.uploadedFileList.filter(item=>item==file.uid)
                //判断是否已上传
                if(!(added && added.length>0)){
                  addFileList.push(file)
                }
            }else if(file.delete && file.uploaded){
                delFileList.push(file)
            }
          })
        }
      })
      if(addFileList.length>0 || delFileList.length>0){
        let promiseArr = []
        addFileList.forEach(file => {
          let promise = new Promise((resolve, reject) => {
            const formData = new FormData();
            formData.append('file', file.originFileObj);
            let url = that.url.uploadAction
            url += "?biz="+file.biz +"&formId="+saveRes.result+"&dataId="+file.dataId
            uploadAction(url, formData).then((res) => {
              if (res.success) {
                resolve(res)
              } else {
                reject(res)
              }
            }).catch((res) => {
              reject(res)
            })
          });
          promiseArr.push(promise)
        });
        delFileList.forEach(file=>{
          let promise = new Promise((resolve, reject) => {
            deleteAction(that.url.deleteFileUrl, {url: file.url, id: file.uid}).then((res) => {
              if (res.success) {
                resolve(res)
              } else {
                reject(that.$t('m.common.tip.deleteFileFailed'))
              }
            })
          });
          promiseArr.push(promise)
        })
        this.confirmLoading ++
        //上传和删除附件处理
        Promise.all(promiseArr).then(res=>{
          that.uploadTimestamp = (new Date()).getTime()+""
          addFileList.forEach(item=>{
            that.uploadedFileList.push(item.uid)
          })
          that.uploadCallback(saveRes,httpurl,formData, func, boKey, p, processDefId)
        }).catch(res=>{
          that.messageUtil.error(res.message);
        }).finally(() => {
          this.confirmLoading --
        })
      }else{
        this.uploadCallback(saveRes,httpurl,formData, func, boKey, p, processDefId)
      }

    },

    afterBpmRefresh(buttonDatas) {
      // 流程动作后事件
      if (this.jsonData && this.jsonData.config && this.jsonData.config.afterBpmRefresh) {
        const func_ext = handleCreateFunc(this.jsonData.config.afterBpmRefresh, this)
        handleExecFunc(func_ext, {buttonDatas})
      }
    }
  }
}
